package cn.zptc.springbootdemo.web;

import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.net.URLEncoder;
import java.util.UUID;

/**
 * @author ：zhaoweiwei
 * @date ：创建于 2025/3/20 13:48
 * @description：
 * @modified By：
 * @version: 1.0.0
 */
@Controller
public class FileController {

    @GetMapping("/toUploadPage")
    public String toUploadPage(){
        return "upload";
    }

    /**
     * uploadFile()方法处理路径为“/uploadFile”的POST请求，对上传文件进行处理。
     * 文件上传处理过程中，对文件名进行重命名并存放在“F:/file/”目录下，并封装了返回结果。
     * 其中，处理上传文件的请求方法中，使用了“MultipartFile[] fileUpload”参数处理单个或多个上传文件（也可以使用单列集合参数），
     * fileUpload参数名必须与upload.html页面中上传文件<input>框中的name属性值一致。
     */
    @PostMapping("/uploadFile")
    public String uploadFile(MultipartFile[] fileUpload, Model model) {

        // 默认文件上传成功，并返回状态信息
        model.addAttribute("uploadStatus", "上传成功！");
        for (MultipartFile file : fileUpload) {
            // 获取文件名以及后缀名
            String fileName = file.getOriginalFilename();
            // 重新生成文件名（根据具体情况生成对应文件名）
            fileName = UUID.randomUUID()+"_"+fileName;
            // 指定上传文件本地存储目录，不存在需要提前创建
            String dirPath = "F:/file/";
            File filePath = new File(dirPath);
            if(!filePath.exists()){
                filePath.mkdirs();
            }

            try {

                file.transferTo(new File(dirPath+fileName));

            } catch (Exception e) {

                e.printStackTrace();
                // 上传失败，返回失败信息
                model.addAttribute("uploadStatus","上传失败： "+e.getMessage());

            }

        }

        // 携带上传状态信息回调到文件上传页面
        return "upload";

    }

    /**
     * 在fileDownload(String filename)方法中，
     * 设定了被下载文件的路径为“F:/file/”、文件下载的打开方式和返回形式；
     *在获取下载结果时，使用了commons-io的FileUtils的readFileToByteArray()方法快速下载文件，
     * 并以ResponseEntity<byte[]>类型数据返回。
     */
    /*@GetMapping("/download")
    public ResponseEntity<byte[]> fileDownload(String filename){

        // 指定要下载的文件根路径
        String dirPath = "F:/file/";
        // 创建该文件对象
        File file = new File(dirPath + File.separator + filename);
        // 设置响应头
        HttpHeaders headers = new HttpHeaders();
        // 通知浏览器以下载方式打开
        headers.setContentDispositionFormData("attachment",filename);
        // 定义以流的形式下载返回文件数据
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        try {

            return new ResponseEntity<>(FileUtils.readFileToByteArray(file), headers, HttpStatus.OK);

        } catch (Exception e) {

            e.printStackTrace();

            return new ResponseEntity<byte[]>(e.getMessage().getBytes(),HttpStatus.EXPECTATION_FAILED);

        }

    }*/

    // 中文文件名下载管理
    @GetMapping("/download")
    public ResponseEntity<byte[]> fileDownload(HttpServletRequest request,
                                               String filename) throws Exception{

        // 指定要下载的文件根路径
        String dirPath = "F:/file/";
        // 创建该文件对象
        File file = new File(dirPath + File.separator + filename);
        // 设置响应头
        HttpHeaders headers = new HttpHeaders();
        // 通知浏览器以下载方式打开（下载前对文件名进行转码）
        filename=getFilename(request,filename);
        headers.setContentDispositionFormData("attachment",filename);
        // 定义以流的形式下载返回文件数据
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        try {

            return new ResponseEntity<>(FileUtils.readFileToByteArray(file), headers, HttpStatus.OK);

        } catch (Exception e) {

            e.printStackTrace();

            return new ResponseEntity<byte[]>(e.getMessage().getBytes(),HttpStatus.EXPECTATION_FAILED);

        }

    }

    // 根据浏览器的不同进行编码设置，返回编码后的文件名
    private String getFilename(HttpServletRequest request, String filename)
            throws Exception {

        // IE不同版本User-Agent中出现的关键词
        String[] IEBrowserKeyWords = {"MSIE", "Trident", "Edge"};
        // 获取请求头代理信息
        String userAgent = request.getHeader("User-Agent");
        for (String keyWord : IEBrowserKeyWords) {
            if (userAgent.contains(keyWord)) {
                //IE内核浏览器，统一为UTF-8编码显示，并对转换的+进行更正
                return URLEncoder.encode(filename, "UTF-8").replace("+","");
            }

        }

        //火狐等其它浏览器统一为ISO-8859-1编码显示
        return new String(filename.getBytes("UTF-8"), "ISO-8859-1");

    }

}
